<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <script type="text/javascript" src="https://lf6-cdn-tos.bytecdntp.com/cdn/expire-1-y/vue/2.6.14/vue.min.js"></script>
    <title>等宽瀑布流-js</title>
    <style>
      .img_box {
        top: 0;
        left: 0;
        position: absolute;
        width: 200px;
        padding: 4px;
      }
      .img_box img {
        max-width: 95%;
      }
    </style>
  </head>
  <body>
    <div id="app">
      <div ref="waterfall">
        <div
          v-for="(item, index) in imgList"
          :key="index"
          class="img_box"
          :style="{ top: item.top + 'px', left: item.left + 'px'}"
        >
          <img :src="item.url" alt="" />
        </div>
      </div>
    </div>
    <script>
      new Vue({
        el: '#app',
        data() {
          return {
            colNumbers: 0,
            colWidth: 200,
            imgList: [],
            colHeight: []
          }
        },
        mounted() {
          this.loadImage()
        },
        methods: {
          // 计算图片列数
          getColNumbers() {
            let clientWidth = this.$refs.waterfall.clientWidth
            this.colNumbers = Math.floor(clientWidth / this.colWidth)
          },
          // 读取图片
          loadImage() {
            this.getColNumbers()
            for (let i = 0; i < 17; i++) {
              let image = new Image()
              let url = `http://www.ruanyifeng.com/images_pub/pub_${i + 1}.jpg`
              image.src = url
              image.onload = () => {
                this.render({
                  index: i,
                  url: url,
                  ratio: image.width / image.height
                })
              }
            }
          },
          render(imgInfo) {
            let colIndex = imgInfo.index % this.colNumbers
            imgInfo.left = colIndex * this.colWidth
            // 首行 top为 0，记录每列的高度
            if (imgInfo.index < this.colNumbers) {
              imgInfo.top = 0
              this.colHeight[colIndex] = this.colWidth / imgInfo.ratio
            } else {
              // 获取高度的最小值
              let minHeight = Math.min.apply(null, this.colHeight)
              let minIndex = this.colHeight.indexOf(minHeight)
              // 此图片的 top 为上面图片的高度，left 相等
              imgInfo.top = minHeight
              imgInfo.left = minIndex * this.colWidth
              // 把高度加上去
              this.colHeight[minIndex] += this.colWidth / imgInfo.ratio
            }
            this.imgList.push(imgInfo)
          }
        }
      })
    </script>
  </body>
</html>
